#ifndef grf_H
#define grf_H

//#include "svl_TNode.h"
#include "gdiP.h"

namespace grf
{

struct TDebug
{
  TDebug() { objectsCount++;}
 ~TDebug() { objectsCount--;}
  //
  static void Check();

private:
  static int objectsCount;
  //
  struct TCheck
  {
   ~TCheck() { TDebug::Check();}
  };
  static TCheck check;
};

////////////////////////////////////////////////////////////////////////////////
struct TImage;
//struct TBitmap;
//struct TBitmapMask;
//struct TIcon;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

struct TPoint : public TDebug
{
  int X,Y;
  //
  TPoint()                { X = Y = 0;}
  TPoint(int X,int Y)     { this->X = X; this->Y = Y;}
  TPoint(POINT Pt)        { X = Pt.x; Y = Pt.y;}
  TPoint(POINTS Pt)       { X = Pt.x; Y = Pt.y;}
  TPoint(const TPoint &V) { *this = V;}
  //
  void MMtoPT(double Scale) { X = svl::MMtoPT(X,Scale); Y = svl::MMtoPT(Y,Scale); }
  void PTtoMM(double Scale) { X = svl::PTtoMM(X,Scale); Y = svl::PTtoMM(Y,Scale); }
  //
  operator POINT() { POINT Pt; Pt.x = X; Pt.y = Y; return Pt;}
  //
  void operator = (const TPoint &V_) { TPoint &V=(TPoint&)V_; X = V.X; Y = V.Y;}
  void operator = (POINTS V)         { X = V.x; Y = V.y;}
  //
  TPoint operator + (TPoint V) { return TPoint(X+V.X,Y+V.Y);}
  TPoint operator - (TPoint V) { return TPoint(X-V.X,Y-V.Y);}
  //
  void Move(int Dx,int Dy) { X += Dx; Y += Dy;}
  //
  int DistanceTo(TPoint Pt);
};

////////////////////////////////////////////////////////////////////////////////

struct TSize : public TDebug
{
  int Width,Height;
  //
  TSize()               { Width = Height = 0;}
  TSize(const TSize &V) { *this = V;}
  TSize(int W,int H)    { Width = W; Height = H;}
  //
  void MMtoPT(double Scale) { Width = svl::MMtoPT(Width,Scale); Height = svl::MMtoPT(Height,Scale); }
  void PTtoMM(double Scale) { Width = svl::PTtoMM(Width,Scale); Height = svl::PTtoMM(Height,Scale); }
  //
  void operator = (const TSize &V_)
  {
    TSize &V = (TSize&)V_; Width = V.Width; Height = V.Height;
  }
  //
  bool operator < (TSize &V) { return Width < V.Width || Height < V.Height;}
};

////////////////////////////////////////////////////////////////////////////////

struct TRect : public TDebug , virtual public svl::TPointer
{
  int Left,Top,Width,Height;
  //
  TRect();
  TRect(const TRect &V) { *this = V;}
  TRect(const TSize &V) { *this = V; Left = Top = 0;}
  TRect(TPoint LT,TSize WH);
  TRect(int L,int T,int W,int H);
  TRect(RECT R);
  //
  void MMtoPT(double Scale);
  void PTtoMM(double Scale);
  //
  operator RECT();
  //operator Windows::TRect();
  //
  TRect &operator = (RECT R);
  TRect &operator = (const TRect &V_)
  {
    TRect &V = (TRect&)V_;
    Left = V.Left; Top = V.Top; Width = V.Width; Height = V.Height; return *this;
  }
  TRect &operator = (const TSize &V_)
  {
    TSize &V = (TSize&)V_; Width = V.Width; Height = V.Height; return *this;
  }
  //
  bool Equal(TRect &V)
  {
    return Left == V.Left && Width  == V.Width &&
           Top  == V.Top  && Height == V.Height;
  }
  //
  void SetLeft(int V)   { Left = V;}
  void SetTop (int V)   { Top  = V;}
  int  Right()          { return Left + Width;}
  void SetRight(int V)  { Width = max(0,V-Left); }
  int  Bottom()         { return Top + Height;}
  void SetBottom(int V) { Height = max(0,V-Top); }
  //
  TPoint LeftTop    () { return TPoint(Left   ,Top     );}
  TPoint LeftBottom () { return TPoint(Left   ,Bottom());}
  TPoint RightTop   () { return TPoint(Right(),Top     );}
  TPoint RightBottom() { return TPoint(Right(),Bottom());}
  //
  void OffsLeftTop(TPoint Delta) { Left += Delta.X; Top += Delta.Y;}
  void  SetLeftTop(TPoint Pt)    { Left  = Pt   .X; Top  = Pt   .Y;}
  //
  TSize Size() { return TSize(Width,Height);}
  //
  bool IsIntersect(TRect &V);
  TRect  Intersect(TRect &V);
  //
  bool IsContainX(int     X) { return Left <= X && X <= Right ();}
  bool IsContainY(int     Y) { return Top  <= Y && Y <= Bottom();}
  bool IsContain (TPoint &V);
  //
  bool IsEqual(TRect &R);
  bool IsEqual(RECT  &R);
  bool IsEmpty() { return Width <= 0 || Height <= 0;}
  //
  TRect ClientToScreen(HWND HWnd);
  //
  bool GetValueByAttrName(svl::TString &AttrName,svl::TString &Value);
  svl::TString GetInfo_Attr();
};

////////////////////////////////////////////////////////////////////////////////

struct TRectArray : public TDebug
{
  void Add(TRect &R) { a.Add(new TObject(R),true);}
  //
  void Clear() { a.Clear();}
  int  Count() { return a.Numb();}
  //
  TRect &Get(int N) { return ((TObject*)a.Get(N))->R;}
  //
  TRect &operator[](int N) { return Get(N);}

private:
  struct TObject : public svl::TArray_Object
  {
    TRect R; TObject(TRect &V) { R = V;}
  };
  svl::TArray a;
};

////////////////////////////////////////////////////////////////////////////////

struct TColor : public TDebug , virtual public svl::TPointer
{
  int R,G,B;
  //
  TColor(const TColor &Color) { *this = Color;}
  TColor() { R = G = B = 0;}
  TColor(int R,int G,int B) { this->R = R; this->G = G; this->B = B;}
  //
  COLORREF ColorRef() { return RGB((BYTE)R,(BYTE)G,(BYTE)B);}
  operator COLORREF() { return RGB((BYTE)R,(BYTE)G,(BYTE)B);}
  //
  void operator = (const TColor &V_) { TColor &V = (TColor&)V_; R = V.R; G = V.G; B = V.B;}
  //
  //void CopyTo(Graphics::TColor *To) { *To = (Graphics::TColor)ColorRef();}
  //
  virtual svl::TInfoParam AddInfoTo(svl::TInfoParam Info);
};

////////////////////////////////////////////////////////////////////////////////

struct TFontStyle : public svl::TSet
{
  enum Enum { Bold,Italic,Underline,StrikeOut};
  svlTSet(TFontStyle,Enum);
  //
  svl::TString GetAsString();
};

////////////////////////////////////////////////////////////////////////////////

struct TFont : public TDebug
{
  svl::TString Name;
  int          Height;
  bool         Bold,Italic,Underline,StrikeOut;
  TColor       Color;
  //
  TFont();
 ~TFont() { ::DeleteObject(handle);}
  //
  void Set(TFontStyle V)
  {
    Bold      = V.Contains(TFontStyle::Bold);
    Italic    = V.Contains(TFontStyle::Italic);
    Underline = V.Contains(TFontStyle::Underline);
    StrikeOut = V.Contains(TFontStyle::StrikeOut);
  }
  //
  operator HFONT() { return handle;}
  //
  void operator = (TFont &V);
  //
  //void CopyTo(Graphics::TFont &To);
  //
  void Update(double Scale = 1);

private:
  HFONT handle;
};

////////////////////////////////////////////////////////////////////////////////

struct TBrush : public TDebug       
{
  HBRUSH HBrush;
  //
  operator HBRUSH() { return HBrush;}
  //
  TBrush(const TBrush &V)
  {
    ::LOGBRUSH LB; ::GetObject(((TBrush&)V).HBrush,sizeof(LB),&LB);
    HBrush = ::CreateBrushIndirect(&LB);
  }
  TBrush(COLORREF V) { HBrush = ::CreateSolidBrush  (V);}
  TBrush(HBITMAP  V) { HBrush = ::CreatePatternBrush(V);}
 ~TBrush()           { ::DeleteObject(HBrush);}
  //
  void operator = (const TBrush &V)
  {
    ::LOGBRUSH LB; ::GetObject(((TBrush&)V).HBrush,sizeof(LB),&LB);
    ::DeleteObject(HBrush); HBrush = ::CreateBrushIndirect(&LB);
  }
  //
  void operator = (TColor V)
  {
    color = V; ::DeleteObject(HBrush);
    HBrush = ::CreateSolidBrush(V.ColorRef());
  }
  //
  TColor Color() { return color;}

private:
  TColor color;
};

////////////////////////////////////////////////////////////////////////////////

struct TPen : public TDebug
{
  HPEN   Handle;
  TColor Color;
  int    Width;
  //
  operator HPEN() { return Handle;}
  //
  TPen(TColor Color,int Width = 1)
  {
    Handle = ::CreatePen(PS_SOLID,Width,Color);
    this->Color = Color;
    this->Width = Width;
  }
  TPen(TPen &V)
  {
    Color  = V.Color;
    Width  = V.Width;
    Handle = ::CreatePen(PS_SOLID,Width,Color);
  }
 ~TPen() { ::DeleteObject(Handle);}
  //
  void Update()
  {
    ::DeleteObject(Handle); Handle = ::CreatePen(PS_SOLID,Width,Color);
  }
  //
  void operator = (TPen &V) { Except("operator = (TPen &V)");}

private:
  svl_Except;
};

////////////////////////////////////////////////////////////////////////////////

struct TRegion : public TDebug
{
  enum ERegionMode
  {
    ERegionMode_And  = RGN_AND,
    ERegionMode_Copy = RGN_COPY,
    ERegionMode_Diff = RGN_DIFF,
    ERegionMode_Or   = RGN_OR,
    ERegionMode_Xor  = RGN_XOR
  };
  //
  TRegion()        { handle = ::CreateRectRgn(0,0,0,0);}
  TRegion(TRect V) { handle = ::CreateRectRgn(V.Left,V.Top,V.Right(),V.Bottom()); }
 ~TRegion()        { ::DeleteObject(handle);}
  //
  void MMtoPT(double Scale);
  void PTtoMM(double Scale);
  //
  void CombineWith(TRegion &V,ERegionMode Mode) { ::CombineRgn(handle,handle,V,Mode);}
  void CombineWith(TRect   &V,ERegionMode Mode) { ::CombineRgn(handle,handle,TRegion(V),Mode);}
  //
  TRegion &operator -= (TRegion &V)
  {
    ::CombineRgn(handle,handle,V.handle,RGN_DIFF); return *this;
  }
  TRegion &operator |= (TRegion &V)
  {
    ::CombineRgn(handle,handle,V.handle,RGN_OR); return *this;
  }
  TRegion &operator = (TRegion &V)
  {
    Except("::operator = (TRegion &V)"); return *this;
  }
  //
  operator HRGN() { return handle;}

private:
  HRGN handle;
  svl_Except;
};

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

struct THBitmap : public TDebug
{
  HBITMAP Handle;
  //
  THBitmap() {}
  //
  operator HBITMAP() { return Handle;}
};

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

struct TImage : public svl::TArray_Object , public TDebug
{
  virtual HGDIOBJ GetGdiObj() = 0;
  virtual HBITMAP GetHBitmap() = 0;
  //
  virtual int Width () = 0;
  virtual int Height() = 0;
  //
  virtual TSize Size() { return TSize(Width(),Height());}
  //
  virtual bool IsTransparent() = 0;
  //
  virtual void LoadFromFile(svl::TString FileName) = 0;
  virtual void TImage_Draw(HDC DC,TRect &Rect) = 0;
  //
  virtual Gdiplus::Bitmap *GetImage()=0;
};

////////////////////////////////////////////////////////////////////////////////




struct TImageGdiP : public TImage
{
  TImageGdiP() { hBmp = NULL;}
 ~TImageGdiP() { ::DeleteObject(hBmp);}

  virtual HGDIOBJ GetGdiObj() { Except("GetGdiObj"); return NULL;}
  virtual HBITMAP GetHBitmap()
  {
    if (!hBmp) { image.GetImage()->GetHBITMAP(Gdiplus::Color(),&hBmp);}
    return hBmp;
  }
  //
  virtual int Width () { return image.Width ();}
  virtual int Height() { return image.Height();}
  //
  virtual bool IsTransparent() { return image.IsTransparent();}
  //
  virtual void LoadFromFile(svl::TString FileName) { image.LoadFromFile(FileName);}
  virtual void TImage_Draw (HDC DC,TRect &Rect)    { image.Draw(DC,Rect.Left,Rect.Top);}
  //
  void operator = (const TImageGdiP &V)
    { Except("operator = (const TImage_GdiP &V)");}
  //
  virtual Gdiplus::Bitmap *GetImage() { return image.GetImage();}

  
private:
  svl_Except;
  gdiP::TImage image;
  HBITMAP hBmp;
};

struct TBorderInfo{
  TImageGdiP *image;
  int t,r,b,l;
  bool multi;
};

////////////////////////////////////////////////////////////////////////////////

struct TImageArray : public TDebug
{
  void Clear() { a.Clear();}
  int  Count() { return a.Numb();}
  //
  void Add(TImage *V,bool EnDelete) { a.Add(V,EnDelete);}
  //
  void AddFromFile(svl::TString FileName)
  {
    TImage *V = new TImageGdiP;
    V->LoadFromFile(FileName); Add(V,true);
  }
  //
  TImage &operator[](int N) { return *(TImage*)a.Get(N);}

private:
  svl::TArray a;
};

////////////////////////////////////////////////////////////////////////////////
}

#endif
